/*
 * Network.h
 *
 *  Created on: 18/11/2011
 *      Author: godinho
 */

#ifndef LV_NETWORK_H_
#define LV_NETWORK_H_

#include <string>
#include <vector>

namespace localview {

class Node;
class Edge;
class Link;
class Phase;

class Network {
public:
	Network();
	virtual ~Network();

	/**
	 * Add a new node to network
	 *
	 * @param n Node object
	 * @return node Index
	 */
	unsigned int addNode(Node* n);

	/**
	 * Add a new edge to a network
	 *
	 * An edge is composed by two nodes.
	 *
	 * @param e Edge object
	 */
	void addEdge(Edge* e);

	/**
	 * Returns a reference to node based in its name
	 *
	 * @param name
	 */
	Node* getNodeByName(std::string name);

	/**
	 * Returns the number of nodes in this network.
	 *
	 * @return number of nodes
	 */
	unsigned int getNodeCount();

	/**
	 * Returns the number of edges on this network.
	 *
	 * @return number of edges
	 */
	unsigned int getEdgeCount();

	/**
	 * Return a node at the position index.
	 *
	 * @param inde of a node on network
	 * @return a reference to the node
	 */
	Node* getNode(unsigned int index);

	/**
	 * Return the edge at the specified index.
	 *
	 * @param inde of the edge
	 * @return reference to the edge object
	 */
	Edge* getEdge(unsigned int index);

	/**
	 * Returns a list of neighbors for a node.
	 *
	 * @param Node* node reference
	 * @return a list of nodes
	 */
	std::vector<Node*> getNodeNeighbors(Node* node);

	/**
	 * Returns  a list of outcoming edges for a node.
	 *
	 * @param Node* node reference
	 * @return a list of edges
	 */
	std::vector<Edge*> getNodeOutcomingEdges(Node* node);

	/**
	 * Returns the number of edges of a node at indunsignedex nodeIndex
	 *
	 * @param nodeIndex
	 */
	int getNodeOutcomingEdgesCount(int nodeIndex);

	/**
	 * Return the edge at adgeIndex for node at nodeIndex.
	 *
	 * @param nodeIndex
	 * @param edgeIndex
	 */
	Edge* getNodeOutcomingEdge(int nodeIndex, int edgeIndex);

	/**
	 * Return the index of node on the network.
	 *
	 * @param Node* node reference
	 * @return index of node
	 */
	int indexOfNode(Node* node);

	/**
	 * Return the index of node on the network.
	 *
	 * @param nodeName
	 * @return index of node;
	 */
	int indexOfNode(std::string nodeName);

	/**
	 * Returns a reference to a named edge.
	 *
	 * @param edge name
	 */
	Edge* getEdgeByName(std::string edge);

	/**
	 * Return a reference to a Edge object if there is a connection
	 * between n1 and n2.
	 *
	 * @param n1 Node 1
	 * @param n2 Node 2
	 */
	Edge* getEdge(Node* n1, Node* n2);

	/**
	 *	This function will traverse all the network graph and call the callback
	 *	function informed on parameters when a node is visited or a node is
	 *	enqueued.
	 *
	 *	A node is enqueued when it is put on the traversal queue, it is visited
	 *	when it is removed from this queue.
	 *
	 *	@param onVisit callback function called when a node is visited
	 *	@param onEnqueue callback function called whan a node is enqueued
	 */
	void widthTraversalGraph(void (*onVisit)(Node*), void (*onEnqueue)(Node*), void (*onVisitEdge)(Edge*));

	/**
	 * Clean traversal status on all network nodes.
	 *
	 * Traversal status indicates if an node was visited, enqueued or neither of
	 * this.
	 */
	void initTraversal();

	/**
	 * Create a Node instance.
	 *
	 * This method was created to python interface get an object controlled by
	 * c++ module
	 */
	Node* createNode(std::string nodeId);

	/**
	 * Create an Edge instance.
	 *
	 * This method was created to python interface get an object controlled by
	 * c++ module
	 */
	Edge* createEdge(Node* from, Node* to, std::string edgeId);

	/**
	 * Create a Link instance.
	 *
	 * This method was created to python interface get an object controlled by
	 * c++ module
	 */
	Link* createLink(Node* from, Node* to);

	/**
	 * Create a Phase instance.
	 *
	 * This method was created to python interface get an object controlled by
	 * c++ module
	 */
	Phase* createPhase();

private:
	std::vector<Node*> mNodes;
	std::vector<Edge*> mEdges;
	std::vector< std::vector<Edge*> > mAdjNodes;
};

}

#endif /* LV_NETWORK_H_ */
